#ifdef KITSCHY_DEBUG_MEMORY 
#include "debug_memorymanager.h"
#endif

#ifdef WIN32
#include "windows.h"
#endif

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "math.h"
#include "pthread.h"

#include "BList.h"
#include "BVector.h"
#include "geometrics.h"
#include "quaternion.h"
#include "symbol.h"
#include "sort.h"
#include "ontology.h"
#include "featureterm.h"
#include "FTKBase.h"

#include "AWEntity.h"
#include "AWMessage.h"
#include "AWBrain.h"
#include "AWTracerBrain.h"
#include "AWThreadedBrain.h"
#include "AWNOOSBrain.h"
#include "AWNOOSLearnerBrain.h"
#include "psm.h"
#include "rFOIL.h"
#include "rINDIE.h"
#include "rINDUCTION.h"
#include "AWNOOSLearnerBrainInduction.h"

#include "CaseBaseUtils.h"


#include "loader.h"



AW_NOOSLearnerBrainInduction::AW_NOOSLearnerBrainInduction(Ontology *O,FTKBase *Memory,FTKBase *CB,bool pause) : AW_NOOSLearnerBrain(O,Memory,CB,pause) 
{
	class_name->set("AW_NOOSLearnerBrainInduction");

	delete m_learning_method;	// overwrite the default value set by AW_NOOSLearnerBrain
	m_learning_method=new Symbol("FOIL3");
	m_hypothesis = 0;

	m_ontology->new_sort("start-distributed-induction","any",0);

} /* AW_NOOSLearnerBrainInduction::AW_NOOSLearnerBrainInduction */ 



AW_NOOSLearnerBrainInduction::AW_NOOSLearnerBrainInduction(FILE *fp,Ontology *O,FTKBase *Memory,FTKBase *CB,bool pause) : AW_NOOSLearnerBrain(O,Memory,CB,pause) 
{
	delete m_learning_method;	// overwrite the default value set by AW_NOOSLearnerBrain
	m_learning_method=new Symbol("FOIL3");
	m_hypothesis = 0;

	m_ontology->new_sort("start-distributed-induction","any",0);

	load(fp);
} /* AW_NOOSLearnerBrainInduction::AW_NOOSLearnerBrainInduction */ 


AW_NOOSLearnerBrainInduction::~AW_NOOSLearnerBrainInduction()
{
	if (m_hypothesis!=0) delete m_hypothesis;
} /* AW_NOOSLearnerBrainInduction::~AW_NOOSLearnerBrainInduction */ 


bool AW_NOOSLearnerBrainInduction::load(FILE *fp) 
{
	if (!AW_NOOSLearnerBrain::load(fp)) return false;

	// TODO: loading hypothesis
	// ...

	return true;
} /* AW_NOOSLearnerBrainInduction::load */ 


bool AW_NOOSLearnerBrainInduction::save(FILE *fp) 
{
	if (!AW_NOOSLearnerBrain::save(fp)) return false;

	// TODO: saving hypothesis
	// ...

	return true;
} /* AW_NOOSLearnerBrainInduction::save */ 


bool AW_NOOSLearnerBrainInduction::is_a(char *c)
{
	if (strcmp(c,"AW_NOOSLearnerBrainInduction")==0) return true;

	return AW_NOOSLearnerBrain::is_a(c);
} /* AW_NOOSLearnerBrainInduction::is_a */ 


bool AW_NOOSLearnerBrainInduction::is_a(Symbol *c)
{
	if (c->cmp("AW_NOOSLearnerBrainInduction")) return true;

	return AW_NOOSLearnerBrain::is_a(c);
} /* AW_NOOSLearnerBrainInduction::is_a */ 


bool AW_NOOSLearnerBrainInduction::process_message(AW_Message *m,FeatureTerm *content)
{	
	Symbol *my_name;
	my_name=m->receiver;

//	write_debug_report("[%s]: message received from %s\n",my_name->get(),m->sender->get());
//	write_debug_report("%s\n",m->content->get());

/*
	{
		char *s;
		s=content->toStringNOOS(m_memory);
		write_debug_report("[%s]: message content: %s\n",m->receiver->get(),s);
		delete []s;
	}
*/
	// learn-message ----------------------------------------------------------------------------------
	if (content->getSort()==m_ontology->get_sort("learn-message")) {
		/* Learn a new case or set of cases: */ 
		FeatureTerm *tmp,*c,*op;
		FeatureTerm *problem=0;	// store a sample case, to infer which is the dataset

		tmp=content->featureValue("case");

		if (tmp->isSet()) {
			List<FeatureTerm> *l;
			l=tmp->set_values();
	
			write_debug_report("[%s]: learnt cases: ",my_name->get());
			while(!l->EmptyP()) {
				c=l->ExtractIni();
				problem = c;
				write_debug_report("%s ",c->getName()->get());
				m_casebase->AddFT(c);
			} /* while */ 
			write_debug_report("\n");
			delete l;
		} else {
			problem = tmp;
			write_debug_report("[%s]: learnt cases: %s\n",my_name->get(),tmp->getName()->get());
			m_casebase->AddFT(new FeatureTerm(tmp));
		} /* if */ 

		op=new FeatureTerm((char *)0,m_ontology->get_sort("status-operator"),1,
						   "text",new FeatureTerm(0,new Symbol(m_learning_method),m_ontology));
		enqueue_operator(op);
		op=FeatureTerm::fromStringNOOS("(define (color-operator) (r 1.0) (g 0.4) (b 0.4))",m_memory,m_ontology);
		enqueue_operator(op);

		// Learn models:
		if (problem!=0) {
			Path dp,sp;
			dp.Add(new Symbol("description"));
			sp.Add(new Symbol("solution"));		

			if (strcmp(problem->getSort()->get(),"sponge")==0) sp.Add(new Symbol("order"));

			if (m_learning_method->cmp("FOIL1")) {
				List<FeatureTerm> *cases=m_casebase->SearchFT(problem->getSort());
				m_hypothesis = new rFOILHypothesis();
				((rFOILHypothesis *)m_hypothesis)->learn(cases,&dp,&sp,m_ontology,m_memory,0);
				cases->ExtractAll();
				delete cases;
			} // if
			if (m_learning_method->cmp("FOIL2")) {
				List<FeatureTerm> *cases=m_casebase->SearchFT(problem->getSort());
				m_hypothesis = new rFOILHypothesis();
				((rFOILHypothesis *)m_hypothesis)->learn2(cases,&dp,&sp,m_ontology,m_memory,0);
				cases->ExtractAll();
				delete cases;
			} // if
			if (m_learning_method->cmp("FOIL3")) {
				List<FeatureTerm> *cases=m_casebase->SearchFT(problem->getSort());
				m_hypothesis = new rFOILHypothesis();
				((rFOILHypothesis *)m_hypothesis)->learn3(cases,&dp,&sp,m_ontology,m_memory,0);
				cases->ExtractAll();
				delete cases;
			} // if
			if (m_learning_method->cmp("INDIE")) {
				List<FeatureTerm> *cases=m_casebase->SearchFT(problem->getSort());
				m_hypothesis = new rINDIEHypothesis();
				((rINDIEHypothesis *)m_hypothesis)->learn(cases,&dp,&sp,m_ontology,m_memory,0);
				cases->ExtractAll();
				delete cases;
			} // if
			if (m_learning_method->cmp("INDIE2C")) {
				List<FeatureTerm> *cases=m_casebase->SearchFT(problem->getSort());
				m_hypothesis = new rINDIEHypothesis();
				((rINDIEHypothesis *)m_hypothesis)->learn2c(cases,&dp,&sp,m_ontology,m_memory,0);
				cases->ExtractAll();
				delete cases;
			} // if
			if (m_learning_method->cmp("INDIE2H")) {
				List<FeatureTerm> *cases=m_casebase->SearchFT(problem->getSort());
				m_hypothesis = new rINDIEHypothesis();
				((rINDIEHypothesis *)m_hypothesis)->learn2h(cases,&dp,&sp,m_ontology,m_memory,0);
				cases->ExtractAll();
				delete cases;
			} // if

//				h=new rINDUCTIONHypothesis();
//				h->learn(cases,dp,sp,o,domain_model);
//				h->learn_single_class(solution,cases,dp,sp,o,domain_model);
//				h->learn2(cases,dp,sp,o,domain_model);
//				h->learn2_single_class(solution,cases,dp,sp,o,domain_model);
//				h->learn3(cases,dp,sp,o,domain_model);
//				h->learn3_single_class(solution,cases,dp,sp,o,domain_model);
//				h->show_rule_set(domain_model);
//				delete h;

			if (m_hypothesis!=0) m_hypothesis->report_rule_set(m_memory);
		}

		op=new FeatureTerm((char *)0,m_ontology->get_sort("status-operator"),1,
						   "text",new FeatureTerm(0,new Symbol("-"),m_ontology));
		enqueue_operator(op);
		op=FeatureTerm::fromStringNOOS("(define (color-operator) (r 0.6) (g 0.6) (b 0.6))",m_memory,m_ontology);
		enqueue_operator(op);

		/* Send back a confirmation: */ 
		op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
						   "receiver",new FeatureTerm(0,new Symbol(m->sender),m_ontology),
						   "content",new FeatureTerm(0,new Symbol("(define (any))"),m_ontology));
		enqueue_operator(op);

		delete tmp;
		return true;
	} /* if */ 

	// forget-message ---------------------------------------------------------------------------------
	if (content->getSort()==m_ontology->get_sort("forget-message")) {
		FeatureTerm *op;

		CB_size.Add(new int(m_casebase->get_n_terms()));
		m_casebase->Delete();
		already_sent_cases_IBA2A.Delete();
		JBartering_refutationsets_agent_name.Delete();
		JBartering_refutationsets.Delete();
		if (m_hypothesis!=0) delete m_hypothesis;
		m_hypothesis=0;
		write_debug_report("[%s]: case base deleted.\n",my_name->get());			

		/* Show statistics: */ 
		// B-CCS
		if (!BCCS_committe_size.EmptyP()) {
			int average=0;
			int i;
			int max=0,*size;
			int *times_per_size;

			BCCS_committe_size.Rewind();
			while(BCCS_committe_size.Iterate(size)) {
				if (*size>max) max=*size;
				average+=*size;
			} /* while */ 

			write_debug_report("[B-CCS : %s]: Average committee size: %g\n",my_name->get(),float(average)/BCCS_committe_size.Length());	

			times_per_size=new int[max];
			for(i=0;i<max;i++) times_per_size[i]=0;
			BCCS_committe_size.Rewind();
			while(BCCS_committe_size.Iterate(size)) {
				times_per_size[(*size)-1]++;
			} /* while */ 
			for(i=0;i<max;i++) {
				write_debug_report("[B-CCS : %s]: Committees of size.%i: %i [%g%%]\n",my_name->get(),i+1,times_per_size[i],float(times_per_size[i])/BCCS_committe_size.Length());	
			} /* for */ 

			delete []times_per_size;

			// Competende model accuracy:
			{
				int total=BCCS_CM_accuracy[0]+BCCS_CM_accuracy[1]+BCCS_CM_accuracy[2]+BCCS_CM_accuracy[3];

				write_debug_report("Competence model Accuracy: \n");
				write_debug_report("                           Correct  Incorrect \n");
				write_debug_report("CM predicted Correct   ->    %.3f     %.3f\n", float(BCCS_CM_accuracy[0])/total,float(BCCS_CM_accuracy[2])/total);
				write_debug_report("CM predicted Incorrect ->    %.3f     %.3f\n", float(BCCS_CM_accuracy[1])/total,float(BCCS_CM_accuracy[3])/total);
				write_debug_report("Accuracy: %g\n", float(BCCS_CM_accuracy[0]+BCCS_CM_accuracy[3])/total);
				write_debug_report("Failed cases because of CM: %i\n", BCCS_CM_accuracy[2]);
			}
			
		} /* if */ 
		// CB size:
		{
			int average=0;
			int *size;

			CB_size.Rewind();
			while(CB_size.Iterate(size)) {
				average+=*size;
			} /* while */ 

			write_debug_report("[%s]: Average CB size: %g\n",my_name->get(),float(average)/CB_size.Length());
		}

		/* Send back a confirmation: */ 
		op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
						   "receiver",new FeatureTerm(0,new Symbol(m->sender),m_ontology),
						   "content",new FeatureTerm(0,new Symbol("(define (any))"),m_ontology));
		enqueue_operator(op);
		return true;
	} /* if */ 

	// start-distributed-induction ----------------------------------------------------------------------------------
	if (content->getSort()==m_ontology->get_sort("start-distributed-induction")) {
		FeatureTerm *op;

		/* ... */ 

		op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
						   "receiver",new FeatureTerm(0,new Symbol(m->sender),m_ontology),
						   "content",new FeatureTerm(0,new Symbol("(define (any))"),m_ontology));
		enqueue_operator(op);
		return true;
	
	} /* if */ 


	return AW_NOOSLearnerBrain::process_message(m,content);
} /* AW_NOOSLearnerBrainInduction::process_message */ 
 


FeatureTerm *AW_NOOSLearnerBrainInduction::build_jers(FeatureTerm *problem,Sort *sort,Symbol *agent_name)
{
	FeatureTerm *solution_record=0;
	Prediction *p=0;

	if (agent_name==0) {
		write_debug_report("[build_jers]: no agent name provided!!!!!\n");
	} /* if */ 

	write_debug_report("[AW_NOOSLearnerBrainInduction]: solving by induction\n");
	
	/* call problem solving method: */ 
	if (m_hypothesis!=0) p = m_hypothesis->generate_prediction(problem,m_memory);

	if (p==0) {
		write_debug_report("[AW_NOOSLearnerBrainInduction]: no prediction could be generated...\n");
		return 0;
	} // if

	/* build solution record: */ 
	write_debug_report("[AW_NOOSLearnerBrainInduction]: proposed %i JERs\n",p->solutions.Length());
	if (p->solutions.Length()==1) {
		solution_record=new FeatureTerm((char *)0,m_ontology->get_sort("problem-prediction"),4,
//										"problem",new FeatureTerm(p->problem),
										"solution",new FeatureTerm(p->solutions[0]),
										"support",new FeatureTerm((char *)0,*p->support[0],m_ontology),
										"justification",new FeatureTerm(p->justifications[0]),
										"agent",new FeatureTerm(0,new Symbol(agent_name),m_ontology));
	} else {
		int i;
		solution_record=FeatureTerm::SetFeatureTerm((Symbol *)0);

		for(i=0;i<p->solutions.Length();i++) {
			solution_record->addSetValue(new FeatureTerm((char *)0,m_ontology->get_sort("problem-prediction"),4,
//														 "problem",new FeatureTerm(p->problem),
														 "solution",new FeatureTerm(p->solutions[i]),
														 "support",new FeatureTerm((char *)0,*p->support[i],m_ontology),
														 "justification",new FeatureTerm(p->justifications[i]),
														 "agent",new FeatureTerm(0,new Symbol(agent_name),m_ontology)));
		} /* for */ 
	} /* if */ 

	delete p;
/*
	{
		char *str;
		str=solution_record->toStringNOOS(m_memory);
		write_debug_report("[AW_NOOSLearnerBrainInduction]: solution:\n%s\n\n",str);
		delete []str;
	}
*/

	return solution_record;
} /* AW_NOOSLearnerBrainInduction::build_jers */ 



FeatureTerm *AW_NOOSLearnerBrainInduction::build_single_jer(FeatureTerm *problem,Sort *sort,Symbol *agent_name)
{
	FeatureTerm *solution_record=0;
	Prediction *p=0;

	if (agent_name==0) {
		write_debug_report("[build_single_jer]: no agent name provided!!!!!\n");
	} /* if */ 

	write_debug_report("[AW_NOOSLearnerBrainInduction]: solving by induction\n");
	
	/* call problem solving method: */ 
	if (m_hypothesis!=0) p = m_hypothesis->generate_prediction(problem,m_memory);

	if (p==0) {
		write_debug_report("[AW_NOOSLearnerBrainInduction]: no prediction could be generated...\n");
		return 0;
	} // if

	/* build solution record: */ 
	write_debug_report("[AW_NOOSLearnerBrainInduction]: proposed %i JERs\n",p->solutions.Length());
	if (p->solutions.Length()==1) {
		write_debug_report("[AW_NOOSLearnerBrainInduction]: support: %i\n",*p->support[0]);
		solution_record=new FeatureTerm((char *)0,m_ontology->get_sort("problem-prediction"),4,
//										"problem",new FeatureTerm(p->problem),
										"solution",new FeatureTerm(p->solutions[0]),
										"support",new FeatureTerm((char *)0,*p->support[0],m_ontology),
										"justification",new FeatureTerm(p->justifications[0]),
										"agent",new FeatureTerm(0,new Symbol(agent_name),m_ontology));
	} else {
		int i;
		int selected=0;

		for(i=0;i<p->solutions.Length();i++) {
			if (*p->support[i]>*p->support[selected]) selected=i;
			write_debug_report("[AW_NOOSLearnerBrainInduction]: support: %i\n",*p->support[i]);
		} /* if */ 
		write_debug_report("[AW_NOOSLearnerBrainInduction]: selected %i\n",selected);

		solution_record=new FeatureTerm((char *)0,m_ontology->get_sort("problem-prediction"),4,
//										"problem",new FeatureTerm(p->problem),
										"solution",new FeatureTerm(p->solutions[selected]),
										"support",new FeatureTerm((char *)0,*p->support[selected],m_ontology),
										"justification",new FeatureTerm(p->justifications[selected]),
										"agent",new FeatureTerm(0,new Symbol(agent_name),m_ontology));
	} /* if */ 

	delete p;
/*
	{
		char *str;
		str=solution_record->toStringNOOS(m_memory);
		write_debug_report("[AW_NOOSLearnerBrainInduction]: solution:\n%s\n\n",str);
		delete []str;
	}
*/

	return solution_record;
} /* AW_NOOSLearnerBrainInduction::build_single_jer */ 

